package com.yys.apm.collect;

import com.yys.apm.boot.AgentBootLoader;
import com.yys.apm.model.CollectInfo;
import com.yys.apm.boot.spi.CollectSPI;
import com.yys.apm.constant.CommonConstant;
import com.yys.apm.logger.ILogger;
import com.yys.apm.logger.LoggerManager;
import com.yys.apm.utils.ApmAgentUtil;
import javassist.CtMethod;

import javax.servlet.http.HttpServletRequest;

/**
 * Service采集器
 *
 * @author Yingsheng Ye
 */
@CollectSPI
public class ServiceCollect extends AbstractApmCollects implements ApmCollect {

    public static ServiceCollect INSTANCE;

    private static final ILogger logger = LoggerManager.getLogger(ServiceCollect.class);

    public ServiceCollect() {
        INSTANCE = this;
    }

    private static final String startSrc;
    private static final String endSrc;
    private static final String errorSrc;

    static {
        StringBuilder sbuilder = new StringBuilder();
        sbuilder.append("com.yys.apm.collect.ServiceCollect instance= ");
        sbuilder.append("com.yys.apm.collect.ServiceCollect.INSTANCE;\r\n");
        sbuilder.append("com.yys.apm.model.CollectInfo collectInfo=instance.start(\"%s\",\"%s\");");
        startSrc = sbuilder.toString();
        sbuilder = new StringBuilder();
        sbuilder.append("instance.end(collectInfo);");
        endSrc = sbuilder.toString();
        sbuilder = new StringBuilder();
        sbuilder.append("instance.error(collectInfo,e);");
        errorSrc = sbuilder.toString();
    }

    public CollectInfo start(String className, String methodName) {
        HttpServletRequest httpServletRequest = ApmAgentUtil.getHttpServletRequest();
        CollectInfo apmDataModel = CollectInfo.build().builder(httpServletRequest, ServiceCollect.class.getSimpleName(),
                null != httpServletRequest ? (String) httpServletRequest.getAttribute(CommonConstant.TRACE_ID) : null,
                null != httpServletRequest ? (String) httpServletRequest.getAttribute(CommonConstant.SPAN_ID) : null, true);
        apmDataModel.setClassName(className);
        apmDataModel.setMethodName(methodName);
        return apmDataModel;
    }

    public void error(CollectInfo collectInfo, Throwable e) {
        collectInfo.setStatus(CommonConstant.FAILED);
        collectInfo.setMsg(e.getMessage());
        collectInfo.put("stackTrace", e.getStackTrace());
    }

    public void end(CollectInfo collectInfo) {
        collectInfo.setEndTime(System.currentTimeMillis());
        collectInfo.setCostTime(collectInfo.getEndTime() - collectInfo.getStartTime());
        this.execute(collectInfo);
    }

    @Override
    public boolean isApmTarget(AgentBootLoader agentLoader) {
        try {
            if (null != agentLoader.getCtClass() && agentLoader.getCtClass().getAnnotations().length > 0) {
                for (Object o : agentLoader.getCtClass().getAnnotations()) {
                    if (o.toString().startsWith("@org.springframework.stereotype.Service")) {
                        return true;
                    }
                }
            }
        } catch (ClassNotFoundException e) {
            logger.error(e, e.getMessage());
        }
        return false;
    }


    @Override
    protected AgentBootLoader.MethodSourceBuild setBuild(String className, CtMethod method) {
        AgentBootLoader.MethodSourceBuild build = new AgentBootLoader.MethodSourceBuild();
        build.setStartSrc(String.format(startSrc, className, method.getName()));
        build.setErrorSrc(errorSrc);
        build.setEndSrc(endSrc);
        return build;
    }

}
